package com.dib.neo.bkfs.server;


import com.dib.neo.bkfs.config.Properties2;

import java.nio.file.Path;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * Server configuration
 *
 * @author dib.yang
 */
public final class BKFSConfiguration {

  private final Properties2 properties;

  public static final String PROPERTY_NODEID = "bkfs.node.id";
  public static final String PROPERTY_MODE = "bkfs.mode";

  /**
   * Accept requests only for TableSpaces for which the local server is leader
   */
  public static final String PROPERTY_ENFORCE_LEADERSHIP = "bkfs.enforce.leadership";
  public static final boolean PROPERTY_ENFORCE_LEADERSHIP_DEFAULT = true;

  public static final String PROPERTY_MODE_LOCAL = "local";
  public static final String PROPERTY_MODE_STANDALONE = "standalone";
  public static final String PROPERTY_MODE_CLUSTER = "cluster";

  public static final String PROPERTY_BASEDIR = "bkfs.base.dir";
  public static final String PROPERTY_BASEDIR_DEFAULT = "${user.dir}/bkfs";
  public static final String PROPERTY_DATADIR = "bkfs.data.dir";
  public static final String PROPERTY_DATADIR_DEFAULT = "data";


  public static final String PROPERTY_ZOOKEEPER_ADDRESS = "bkfs.zookeeper.address";
  public static final String PROPERTY_ZOOKEEPER_SESSIONTIMEOUT = "bkfs.zookeeper.session.timeout";
  //public static final String PROPERTY_ZOOKEEPER_PATH = "bkfs.zookeeper.path";

  public static final String PROPERTY_BOOKKEEPER_START = "bkfs.bookkeeper.start";
  public static final boolean PROPERTY_BOOKKEEPER_START_DEFAULT = false;

  public static final String PROPERTY_BOOKKEEPER_BOOKIE_PORT = "bkfs.bookkeeper.port";
  public static final int PROPERTY_BOOKKEEPER_BOOKIE_PORT_DEFAULT = 3181;

  public static final String PROPERTY_BOOKKEEPER_ENSEMBLE = "bkfs.bookkeeper.ensemble.size";
  public static final int PROPERTY_BOOKKEEPER_ENSEMBLE_DEFAULT = 3;
  public static final String PROPERTY_BOOKKEEPER_WRITEQUORUMSIZE = "bkfs.bookkeeper.write.quorum.size";
  public static final int PROPERTY_BOOKKEEPER_WRITEQUORUMSIZE_DEFAULT = 2;
  public static final String PROPERTY_BOOKKEEPER_ACKQUORUMSIZE = "bkfs.bookkeeper.ack.quorum.size";
  public static final int PROPERTY_BOOKKEEPER_ACKQUORUMSIZE_DEFAULT = 2;
  public static final String PROPERTY_BOOKKEEPER_LEDGERS_RETENTION_PERIOD = "bkfs.bookkeeper.ledgers.retention.period";
  public static final long PROPERTY_BOOKKEEPER_LEDGERS_RETENTION_PERIOD_DEFAULT =
      1000L * 60 * 60 * 24 * 2;

  public static final String PROPERTY_BOOKKEEPER_MAX_IDLE_TIME = "bkfs.bookkeeper.max.idle.time";
  public static final long PROPERTY_BOOKKEEPER_MAX_IDLE_TIME_DEFAULT = 1000L * 10;

  public static final String PROPERTY_ZOOKEEPER_ADDRESS_DEFAULT = "localhost:1281";
  public static final int PROPERTY_ZOOKEEPER_SESSIONTIMEOUT_DEFAULT = 40000;

  public BKFSConfiguration(Properties properties) {
    this.properties = new Properties2();
    this.properties.putAll(properties);
  }

  public BKFSConfiguration(Path baseDir) {
    this();
    set(PROPERTY_BASEDIR, baseDir.toAbsolutePath());
  }


  /**
   * Copy configuration
   */
  public BKFSConfiguration copy() {
    Properties2 copy = new Properties2();
    copy.putAll(this.properties);
    return new BKFSConfiguration(copy);
  }

  public BKFSConfiguration() {
    this.properties = new Properties2();
  }

  public void load(Properties properties) {
    if (properties != null) {
      this.properties.putAll(properties);
    }
  }

  public boolean getBoolean(String key, boolean defaultValue) {
    final String value = this.properties.getProperty(key);

    if (value == null || value.isEmpty()) {
      return defaultValue;
    }

    return Boolean.parseBoolean(value);
  }

  public int getInt(String key, int defaultValue) {
    final String value = this.properties.getProperty(key);

    if (value == null || value.isEmpty()) {
      return defaultValue;
    }

    return Integer.parseInt(value);
  }

  public long getLong(String key, long defaultValue) {
    final String value = this.properties.getProperty(key);

    if (value == null || value.isEmpty()) {
      return defaultValue;
    }

    return Long.parseLong(value);
  }

  public double getDouble(String key, double defaultValue) {
    final String value = this.properties.getProperty(key);

    if (value == null || value.isEmpty()) {
      return defaultValue;
    }

    return Double.parseDouble(value);
  }

  public String getString(String key, String defaultValue) {
    return this.properties.getProperty(key, defaultValue);
  }

  public BKFSConfiguration set(String key, Object value) {
    if (value == null) {
      this.properties.remove(key);
    } else {
      this.properties.setProperty(key, value + "");
    }
    return this;
  }

  @Override
  public String toString() {
    return "BKFSConfiguration{" + "properties=" + properties + '}';
  }

  private static final Logger LOG = Logger.getLogger(BKFSConfiguration.class.getName());

  public List<String> keys() {
    return properties.keySet().stream().map(Object::toString).sorted().collect(Collectors.toList());
  }

  public static BKFSConfiguration load(String conf) {
    return null;
  }

}

